import os
import logging
import datetime
import urllib
from xml.etree import ElementTree

from django import http
from django.utils import simplejson
from django.template import loader
from django.shortcuts import render_to_response
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from google.appengine.ext import webapp
from google.appengine.api import urlfetch
from google.appengine.api import users

from . import models
from . import forms

def index(request):
    raise http.Http404
    return http.HttpResponseRedirect('http://code.google.com/p/appspot-lidaobing/')

def ohloh(request, account):
    format = request.GET.get('format', 'rss')

    try:
        records = getOhloh(account)
    except OhlohApiKeyNotSet:
        return http.HttpResponseRedirect(reverse('ohloh2rss') + '?action=editKey')

    if records is None:
        raise http.Http404

    if format == 'json':
        return _toJson(records)
    elif format == 'rss':
        return _toRss(records)

    raise http.Http404

def _toRss(records):
    account = records[0].account
    response = http.HttpResponse()

    path = os.path.join(os.path.dirname(__file__), 'account.xml')
    response.headers['Content-Type'] = 'text/xml; charset="utf-8"'
    response.write(loader.render_to_string('ohloh2rss/account.xml', locals()))
    return response

def _toJson(records):
    raise http.Http404

class OhlohApiKeyNotSet(RuntimeError):
    pass

def ohloh2rank(account):
    urltemp = 'https://www.ohloh.net/accounts/%(account)s.xml?api_key=%(key)s'

    try:
        key = models.ApiKey.all()[0].name
    except IndexError:
        raise OhlohApiKeyNotSet

    url = urltemp % locals()
    res = urlfetch.fetch(url)
    if res.status_code != 200:
        return None

    elem = ElementTree.fromstring(res.content)
    error = elem.find('error')
    if error is not None:
        logging.error('Ohloh returned: %s' % ElementTree.tostring(error))
        return None

    res2 = {}
    for k in ['position', 'kudo_rank', 'max_position']:
        x = elem.find('result/account/kudo_score/' + k)
        if x is None:
            logging.error('ohloh response format changed? %r' % res.content)
            return None
        res2[k] = int(x.text)
    return res2

def getOhloh(account, n=10):
    if n >= 0:
        records = models.Ohloh.all().filter('account =', account).order('-createat')[:n]
    else:
        records = list(models.Ohloh.all().filter('account =', account).order('-createat'))
    if len(records) == 0 or records[0].createat.date() != datetime.datetime.utcnow().date():
        record = ohloh2rank(account)
        if record is not None:
            record = models.Ohloh(account=account,
                                  kudo_rank=record['kudo_rank'],
                                  position = record['position'],
                                  max_position = record['max_position'])
            record.put()
            records = [record] + records
    if not records:
        return None
    if n >= 0:
        return records[:n]
    else:
        return records

class PngHandler(webapp.RequestHandler):
    def get(self, account):
        records = getOhloh(account, -1)
        records = records[::-1]
        if records is None:
            self.response.set_status(404)
            return
        positions = [x.position for x in records]
        #positions = [1,2,4,4,5]
        min_position = min(positions)
        max_position = max(positions)
        min_date = records[0].createat
        max_date = records[-1].createat

        if min_position == max_position:
            data = [50] * max(len(positions), 2)
        else:
            data = []
            for x in positions:
                data.append(float(max_position-x)*100/(max_position-min_position))

        chxl = '0:|%s|%s' % (max_position, min_position)
        chxl += '|'
        chxl += '1:|%s|%s' % (min_date.isoformat()[:10], max_date.isoformat()[:10])

        url = 'http://chart.apis.google.com/chart?' + urllib.urlencode({'cht': 'lc',
                                          'chd': 't:%s' % ','.join([str(x) for x in data]),
                                          'chs': '250x125',
                                          'chtt': account,
                                          'chxt': 'y,x',
                                          'chxl': chxl,
                                          })
        fetchResult = urlfetch.fetch(url)
        if fetchResult.status_code != 200:
            logging.error('fetch url %r failed: %r' % (url, fetchResult))
            self.response.set_status(500)
            return
        del self.response.headers['Content-Type']
        self.response.headers.add_header('Content-Type', 'image/png')
        self.response.out.write(fetchResult.content)

class MainHandler(webapp.RequestHandler):
    def get(self, account):
        format = self.request.get('format', 'rss').lower()

        if not hasattr(self, 'to_' + format):
            self.response.set_status(400) # Bad Request
            return

        records = getOhloh(account)
        if records is None:
            self.response.set_status(404)
            return

        getattr(self, 'to_' + format)(records)


    def to_json(self, records):
        del self.response.headers['Content-Type']
        self.response.headers.add_header('Content-Type', 'text/plain')

        self.response.out.write(simplejson.dumps([x.to_dict() for x in records], indent=2))

@login_required
def editKey(request):
    if not users.is_current_user_admin():
        return http.HttpResponseRedirect(users.create_logout_url(request.get_full_path()))

    if request.method == 'POST':
        form = forms.EditKeyForm(request.POST)
        if form.is_valid():
            form.save()
            return http.HttpResponseRedirect('/')
    else:
        form = forms.EditKeyForm()
    return render_to_response('ohloh2rss/editKey.html', locals())

def processRoot(request):
    action = request.REQUEST.get('action', 'index')
    if action == 'index':
        return index(request)
    elif action == 'editKey':
        return editKey(request)
    raise http.Http404
